﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using UserLINQ.Repository.Interfaces;
using UserLINQ.Types;

namespace UserLINQ.BLL
{
	/// <summary>
	/// класс-расширения
	/// </summary>
	public static class Extensions
	{
		/// <summary>
		/// Определим тип перечисления порядка сортировки
		/// </summary>
		public enum SortDirection
		{
			/// <summary>
			/// По возрастанию
			/// </summary>
			Ascending,
			/// <summary>
			/// По убыванию
			/// </summary>
			Descending
		}

		/// <summary>
		/// Статический Generic-метод сортировки коллекции по заданному атрибуту
		/// </summary>
		/// <typeparam name="T">Тип коллекции</typeparam>
		/// <param name="source">Исходная коллекция</param>
		/// <param name="attribute">Имя поля сортировки</param>
		/// <param name="sortDirection">Порядок сортировки</param>
		/// <returns>Упорядоченная коллекция</returns>
		public static IEnumerable<T> Sort<T>(this IEnumerable<T> source, string field, SortDirection sortDirection)
		{
			// Динамически создадим параметр коллекции
			var param = Expression.Parameter(typeof(T), "item");
			// Динамически создадим лямда-выражение сортировки
			var sortExpression = Expression.Lambda<Func<T, object>>
			(
			   Expression.Convert
			   (
				  Expression.Property(param, field),
				  typeof(object)
			   ),
			   param
			);

			// В зависимости от порядка сортировки упорядочим коллекцию с помощью OrderBy
			switch (sortDirection)
			{
				case SortDirection.Ascending:
					{
						return source.AsQueryable().OrderBy<T, object>(sortExpression);
					}

				default:
					{
						return source.AsQueryable().OrderByDescending<T, object>(sortExpression);
					}
			}
		}

	}

	/// <summary>
	/// Реализация фильтра по ФИО
	/// </summary>
	public class FilterFIO : IFilter<User>
	{
		// Имя
		public string FirstName { get; set; }
		// Отчество
		public string Patronymic { get; set; }
		// Фамилия
		public string LastName { get; set; }
		/*
		public static IQueryable OrderBy(this IQueryable source, string fieldName)
		{
			return OrderBy(source, fieldName, SortDirection.Ascending);
		}
		 */

		/// <summary>
		/// Реализация фильтра из интерфейса IFilter
		/// </summary>
		/// <param name="users">Список пользователей</param>
		/// <returns>Отфильтрованный список</returns>
		IEnumerable<User> IFilter<User>.Filter(List<User> users)
		{
			// c помощью LINQ IQueryable отфильтруем список и вернём его
			return from User usr in users
				   where usr.LastName.Contains(LastName) &&
							   usr.FirstName.Contains(FirstName) &&
							   usr.Patronymic.Contains(Patronymic)
				   //orderby usr.LastName
				   select usr;
		}
		public FilterFIO()
		{
			FirstName = "";
			Patronymic = "";
			LastName = "";
		}

	}

	/// <summary>
	/// Класс Бизнес-логики пользователя
	/// </summary>
	public class UserBLL
	{
		// поле репозитория
        IUserRepository _repository;
		// поле списка пользователей из репозитория
		private List<User> _users;
		/// <summary>
		/// конструктор
		/// </summary>
		/// <param name="repository">Репозиторий пользователей</param>
		public UserBLL(IUserRepository repository)
        {
            _repository = repository;
			// Получим список пользоватей из репозитория
			_users = _repository.GetUsers();
        }

		/// <summary>
		/// Метод интерфейса получения списка пользователей из репозитория пользователей
		/// </summary>
		/// <returns>Список пользователей</returns>
		public List<User> GetUsers()
        {
			return _repository.GetUsers();
        }

		#region IFilter<User> Members

		// private-поле хранит текущий фильтр
		private IFilter<User> _filter;

		/// <summary>
		/// Public свойство устанавливает фильтр
		/// </summary>
		public IFilter<User> Filter
		{
			get
			{
				return _filter;
			}
			set
			{
				_filter = value;
			}
		}

		#endregion

		/// <summary>
		/// При обращении к Users происходит фильтрация списка пользователей (если фильтр установлен)		
		/// </summary>
		public IEnumerable<User> Users
		{
			get
			{
				if (_filter == null)
					return _users;
				else
				{
					return _filter.Filter(_users);						
				}
			}
		}

	} // class UserBLL
}
